const Generator = require('yeoman-generator');
const fs = require('fs');
const path = require('path')


class Base extends Generator {
  static PROJECT = 'project';
  static SPIDERS = 'spiders';
  static MODULE = 'module';
  static TMPL_EXT = '.tmpl';
  static PY_EXT = '.py';
  static SCRAPY_CONFIG_FILE = 'scrapy.cfg';

  static TMPL_ROOT = path.resolve(__dirname, '../templates');

  static TMPL_PROJECT_ROOT = this.getAbsolutePath(this.TMPL_ROOT, this.PROJECT);
  static TMPL_PROJECT_MODULE_ROOT = this.getAbsolutePath(this.TMPL_PROJECT_ROOT, this.MODULE);
  static TMPL_PROJECT_FILES = this.getFiles(this.TMPL_PROJECT_ROOT);
  static TMPL_PROJECT_MODULE_FILES = this.getFiles(this.TMPL_PROJECT_MODULE_ROOT);
  static TMPL_PROJECT_OTHER_FILES = this.TMPL_PROJECT_FILES.filter(file => !this.TMPL_PROJECT_MODULE_FILES.includes(file));

  static TMPL_SPIDER_ROOT = this.getAbsolutePath(this.TMPL_ROOT, this.SPIDERS);
  static TMPL_SPIDER_FILES = this.getFiles(this.TMPL_SPIDER_ROOT);

  // spider 模块名就是 spiders/ 目录下的去除后缀的名字
  static TMPL_SPIDER_NAMES = this.TMPL_SPIDER_FILES.map(this.getSpiderTemplateName);

  static validationName(string) {
    if (/^[_a-zA-Z]([_a-zA-Z\d]){0,62}$/.test(string)) {
      return true;
    }
    return '由字母, 数字, 下划线组成, 不能以数字开头, 长度为 1 ~ 63';
  }

  // DNS规定，域名中的标号都由英文字母和数字组成，每一个标号不超过63个字符，也不区分大小写字母。
  // 标号中除连字符（-）外不能使用其他的标点符号。级别最低的域名写在最左边，而级别最高的域名写在最右边。
  // 由多个标号组成的完整域名总共不超过255个字符。
  static validationDomain(string) {
    if (/^(?=^.{3,255}$)[a-zA-Z0-9][-a-zA-Z0-9]{0,62}(\.[a-zA-Z0-9][-a-zA-Z0-9]{0,62})+$/.test(string)) {
      return true;
    }
    return '请正确输入域名';
  }

  static validationEmail(string) {
    if (/^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/.test(string)) {
      return true;
    }
    return '请正确输入邮箱';
  }

  static title(string) {
    return string.charAt(0).toUpperCase() + string.substring(1);
  }

  /**
   * Convert a word to its CamelCase version and remove invalid chars
   * stringCamelcase('lost-pound')     -- > LostPound
   * stringCamelcase('missing_images') -- > MissingImages
   * @param {} string 
   */
  static stringCamelcase(string) {
    return string.split(/[^a-zA-Z\d]/).map(this.title).join('');
  }

  // 获取文件绝对路径
  static getAbsolutePath(...paths) {
    return path.resolve(...paths);
  }
  
  // 获取文件夹路径的文件名称
  static getFolderName(dir) {
    try {
      dir = path.resolve(dir);
      const parse = path.parse(dir);
      const isDir = fs.statSync(dir).isDirectory();
      if (isDir) {
        return parse.name;
      }
      const pathSplit = parse.dir.split(path.sep);
      return pathSplit[pathSplit.length - 1];
    } catch (e) {
      throw new Error(e);
    }
  }
  
  // 判断文件夹或文件是否已存在
  static existsPath(...paths) {
    try {
      fs.accessSync(path.resolve(...paths));
      return true;
    } catch (e) {
      return false;
    }
  }

  // 递归遍历获取文件
  static getFiles(dir) {
    let res = [];
    const dirOrfiles = fs.readdirSync(dir);
    for (const dirOrfile of dirOrfiles) {
      const file = path.join(dir, dirOrfile);
      const isDirectory = fs.statSync(file).isDirectory();
      if (isDirectory) {
        res = res.concat(this.getFiles(file));
      } else {
        res.push(file);
      }
    }
    return res;
  }

  static getSpiderTemplateName(file) {
    return path.basename(file).split('.', 1)[0];
  }

  static renameTmplFileExt(file) {
    if (file.endsWith('.py.tmpl')) {
      return file.replace(/.py.tmpl$/, '.py');
    } else if (file.endsWith('.tmpl')) {
      return file.replace(/.tmpl$/, '.py');
    } else {
      return file;
    }
  }

  static renamePath(from, to) {
    return fs.renameSync(from, to);
  }
}

module.exports = { Base };